package cn.w.outdoor.lib.network;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import cn.w.outdoor.lib.common.CommonMethods;
import cn.w.outdoor.lib.model.Intercom_Msg;
import cn.w.outdoor.lib.model.PCMSG;

/**
 * 说明 此部分分为
 */
public class TCPTools {

    private final List<OnDataListener> dataListenerList = new CopyOnWriteArrayList<>();

    public interface OnDataListener {
        void onData(String remoteIpAddr, byte[] data);
    }

    public void addDataListener(OnDataListener dataListener) {
        if (dataListener != null && !dataListenerList.contains(dataListener)) {
            dataListenerList.add(dataListener);
        }
    }

    public void removeDataListener(OnDataListener dataListener) {
        if (dataListener != null) {
            dataListenerList.remove(dataListener);
        }
    }

    private final static int TCP_INTERCOM_MSG_PORT = 0x4321;
    private final static int TCP_MESSAGE_PORT = 0x8866;

    private static final TCPTools ourInstance = new TCPTools();

    public static TCPTools getInstance() {
        return ourInstance;
    }

    private TCPTools() {
        startTCPTools();
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                stopTCPTools();
            }
        });
    }

    private final AtomicBoolean controll = new AtomicBoolean(false);

    private TCPServerSocketThread tcpServerSocketThread = null;

    public void startTCPTools() {
        synchronized (controll) {
            if (!controll.get()) {
                if (tcpServerSocketThread == null) {
                    tcpServerSocketThread = new TCPServerSocketThread();
                    tcpServerSocketThread.start();
                }
            } else {
                System.err.println("TCPTools 已经执行了初始化操作，无法再次执行");
            }
        }
    }

    public void stopTCPTools() {
        synchronized (controll) {
            if (controll.get()) {
                if (tcpServerSocketThread != null) {
                    tcpServerSocketThread.threadStop();
                }
            } else {
                System.err.println("TCPTools 尚未执行初始化操作");
            }
        }
    }

    public int sendPCMSGTo(PCMSG pcmsg, String remoteIpAddr) {
        System.out.println("发送消息");
        return sendInfo(pcmsg.generateToBytes(), remoteIpAddr, TCP_MESSAGE_PORT);
    }

    public int sendIntercomMSGTo(Intercom_Msg intercom_msg, String remoteIpAddr) {
        System.out.println("发送指令 " + remoteIpAddr + " " + intercom_msg.toString());
        return sendInfo(intercom_msg.generateToBytes(), remoteIpAddr, TCP_INTERCOM_MSG_PORT);
    }

    private int sendInfo(byte[] sendData, String remoteIpAddr, int remotePort) {
        System.out.println("发送数据 长度：" + sendData.length + " " + remoteIpAddr + ":" + remotePort + " " + CommonMethods.byte2hex(sendData));

        int returnValue = 0;
        Socket socket = null;
        try {
            socket = new Socket(remoteIpAddr, remotePort);
            OutputStream os = socket.getOutputStream();
            os.write(sendData);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("Socket 连接失败");
            returnValue = 1;
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return returnValue;
    }

    private class TCPServerSocketThread extends Thread {

        private ServerSocket serverSocket = null;

        private boolean threadStoper = false;

        public void threadStop() {
            this.threadStoper = true;
        }

        public TCPServerSocketThread() {

        }

        @Override
        public void run() {
            try {
                serverSocket = new ServerSocket(TCP_INTERCOM_MSG_PORT);
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (serverSocket != null) {

                while (!this.threadStoper) {
                    try {
                        Socket socket = serverSocket.accept();
                        InetSocketAddress socketAddress = (InetSocketAddress) socket.getRemoteSocketAddress();
                        InputStream inputStream = socket.getInputStream();
                        int checkCount = 3;
                        while (checkCount > 0 && !this.threadStoper) {
                            if (inputStream.available() == 92) {
                                byte[] intercomMsg = new byte[92];
                                if (inputStream.read(intercomMsg, 0, 92) == 92) {
                                    System.out.println("收到数据 " + socketAddress.getHostString() + " " + new Intercom_Msg(intercomMsg).toString() + CommonMethods.byte2hex(intercomMsg));
                                    for (OnDataListener dataListener : dataListenerList) {
                                        if (dataListener != null) {
                                            dataListener.onData(socketAddress.getHostString(), intercomMsg);
                                        }
                                    }
                                    break;
                                }
                            } else {
                                checkCount--;
                                try {
                                    TimeUnit.MILLISECONDS.sleep(100);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}
